home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / ntunzip2.zip / UNZIP.C < prev    next >
C/C++ Source or Header  |  1994-02-10  |  55KB  |  1,500 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   unzip.c
  4.  
  5.   UnZip - a zipfile extraction utility.  See below for make instructions, or
  6.   read the comments in Makefile and the various Contents files for more de-
  7.   tailed explanations.  To report a bug, send a *complete* description to
  8.   zip-bugs@wkuvx1.wku.edu; include machine type, operating system and ver-
  9.   sion, compiler and version, and reasonably detailed error messages or prob-
  10.   lem report.  To join Info-ZIP, see the instructions in README.
  11.  
  12.   UnZip 5.x is a greatly expanded and partially rewritten successor to 4.x,
  13.   which in turn was almost a complete rewrite of version 3.x.  For a detailed
  14.   revision history, see UnzpHist.zip at quest.jpl.nasa.gov.  For a list of
  15.   the many (near infinite) contributors, see "CONTRIBS" in the UnZip source
  16.   distribution.
  17.  
  18.   ---------------------------------------------------------------------------
  19.  
  20.   [from original zipinfo.c]
  21.  
  22.   This program reads great gobs of totally nifty information, including the
  23.   central directory stuff, from ZIP archives ("zipfiles" for short).  It
  24.   started as just a testbed for fooling with zipfiles, but at this point it
  25.   is actually a useful utility.  It also became the basis for the rewrite of
  26.   UnZip (3.16 -> 4.0), using the central directory for processing rather than
  27.   the individual (local) file headers.
  28.  
  29.   The author finds it convenient to define an alias "ii" (under Unix and VMS)
  30.   or to rename the executable to "ii.exe" (OS/2 and DOS).  This nicely comple-
  31.   ments the common Unix "ll" long-listing alias (ls -lF), since zipinfo's de-
  32.   fault action is to produce a Unix-like listing of the archive's contents.
  33.   "ii zipfile" is easier to type than "zipinfo zipfile"...
  34.  
  35.   As of ZipInfo v2.0 and UnZip v5.1, the two programs are combined into one.
  36.   If the executable is named "unzip" (or "unzip.exe", depending), it behaves
  37.   like UnZip by default; if it is named "zipinfo" or "ii", it behaves like
  38.   ZipInfo.  The ZipInfo behavior may also be triggered by use of unzip's -Z
  39.   option; for example, "unzip -Z [zipinfo_options] archive.zip".
  40.  
  41.   Another dandy product from your buddies at Newtware!
  42.  
  43.   Author:  Greg Roelofs, newt@uchicago.edu, 23 August 1990 -> ...
  44.            SizeOfEAs() by Kai Uwe Rommel.
  45.  
  46.   ---------------------------------------------------------------------------
  47.  
  48.   Quick compile instructions (see INSTALL file):  copy and/or rename appro-
  49.   priate makefile to main unzip directory, then:
  50.  
  51.      under Unix (cc):  make <system name>
  52.        (type "make list" for a list of valid names, or read Makefile for 
  53.         details.  "make unzip" works for most systems.  If you have a NEW
  54.         system, not covered by any of the existing targets, send FULL in-
  55.         formation--hardware, OS, versions, etc.--to zip-bugs)
  56.  
  57.      under VMS (VAX or Alpha C, or GNU C):  @make_vaxc  or  @make_gcc
  58.        (can also use MMS or MAKE/VMS; see [.vms]README.)
  59.  
  60.      under OS/2:  nmake -f makefile.os2 <compiler>
  61.        (type "nmake -f makefile.os2" for list of targets; Watcom, Borland,
  62.         IBM, Microsoft, emx+gcc compilers and nmake and dmake supported)
  63.  
  64.      under MS-DOS (MS or Quick C, Turbo or Borland C[++]):  make
  65.        (project files no longer supported; for Microsoft, use nmake; for
  66.         djgpp or cross-compiling, use appropriate targets in unix/Makefile)
  67.  
  68.      under MS Windows 3.1:  get wunz20sr.{zip | zoo | whatever} and use
  69.        the included makefile
  70.  
  71.      under Windows NT (MS Visual C++):  nmake
  72.  
  73.      under Macintosh OS (Think C):  un-BinHex the Think C project file and
  74.        UnZip resource file, then click on something or other :-) )
  75.  
  76.      under AmigaDOS (SAS/Lattice C or Aztec C):
  77.        with SAS C 6.x:  lmk -f amiga/SMakeFile all
  78.        with Aztec C:    make -f amiga/Makefile.AZT all
  79.  
  80.      under Atari TOS (MiNT libraries and gcc 2.4.5):  make
  81.        (see atari/README and atari/Makefile for info about other compilers)
  82.  
  83.      under TOPS-20:  use make.mic and "do make" [no longer fully ported]
  84.  
  85.   ---------------------------------------------------------------------------
  86.  
  87.   Version:  unzip51.{tar.Z | zip | zoo} for Unix, VMS, OS/2, MS-DOS, Windows,
  88.               Windows NT, Macintosh, Amiga, Atari and TOPS-20.  Decryption
  89.               requires sources in zcrypt20.zip, and Windows (not NT) support
  90.               requires sources in wunz20sr.zip.  See accompanying file "Where"
  91.               in the main source distribution for ftp, uucp and mail-server
  92.               sites.
  93.   Copyrights:  see accompanying file "COPYING" in UnZip source distribution.
  94.  
  95.   ---------------------------------------------------------------------------*/
  96.  
  97.  
  98.  
  99. #include "unzip.h"               /* includes, typedefs, macros, etc. */
  100. #ifdef MSWIN
  101. #  include "wizunzip.h"
  102. #endif
  103.  
  104.  
  105. #define RELEASE
  106. #ifdef RELEASE
  107. #  define UZ_VERSION  "5.1 of 7 February 1994"   /* official release version */
  108. #  define ZI_VERSION  "2.0 of 7 February 1994"
  109. #else
  110. #  define UZ_VERSION  "5.1p BETA of 6 Feb 94"   /* internal beta level */
  111. #  define ZI_VERSION  "1.99 BETA of 6 Feb 94"
  112. #endif
  113.  
  114.  
  115.  
  116. /**********************/
  117. /*  Global Variables  */
  118. /**********************/
  119.  
  120. #ifdef MACOS
  121.    extern char *unzip_version = UZ_VERSION;
  122.    extern char *zipinfo_version = ZI_VERSION;
  123. #endif
  124.  
  125. int zipinfo_mode;     /* behave like ZipInfo or like normal UnZip? */
  126.  
  127. int aflag=0;          /* -a: do ASCII-EBCDIC and/or end-of-line translation */
  128. int cflag=0;          /* -c: output to stdout */
  129. int dflag=0;          /* -d: all args are files/dirs to be extracted */
  130. int fflag=0;          /* -f: "freshen" (extract only newer files) */
  131. int hflag=0;          /* -h: header line (zipinfo) */
  132. int jflag=0;          /* -j: junk pathnames (unzip) */
  133. int lflag=(-1);       /* -12slmv: listing format (zipinfo) */
  134. int overwrite_none=0; /* -n: never overwrite files (no prompting) */
  135. int overwrite_all=0;  /* -o: OK to overwrite files without prompting */
  136. int force_flag=0;     /* (shares -o for now): force to override errors, etc. */
  137. int qflag=0;          /* -q: produce a lot less output */
  138. #ifdef DOS_NT_OS2
  139.    int sflag=0;       /* -s: convert filename spaces (blanks) to underscores */
  140.    int volflag=0;     /* -$: extract volume labels */
  141. #endif
  142. int tflag=0;          /* -t: test (unzip) or totals line (zipinfo) */
  143. int uflag=0;          /* -u: "update" (extract only newer & brand-new files) */
  144. int U_flag=0;         /* -U: preserve uppercase characters in filenames */
  145. int vflag=0;          /* -v: (verbosely) list directory */
  146. int V_flag=0;         /* -V: don't strip VMS version numbers */
  147. #ifdef VMS
  148.    int secinf=0;      /* -X: keep owner/protection */
  149. #endif
  150. int zflag=0;          /* -z: display the zipfile comment (only, for unzip) */
  151.  
  152. int filespecs;        /* number of real file specifications to be matched */
  153. int xfilespecs;       /* number of excluded filespecs to be matched */
  154. int process_all_files = 0;
  155. int create_dirs;      /* used by main(), mapname(), checkdir() */
  156. int extract_flag;
  157.  
  158. LONGINT real_ecrec_offset, expect_ecrec_offset;
  159.  
  160. long csize;           /* used by list_files(), ReadByte(): must be signed */
  161. long ucsize;          /* used by list_files(), unReduce(), explode() */
  162. long used_csize;      /* used by extract_or_test_member(), explode() */
  163.  
  164. static char *fnames[2] = {"*", NULL};   /* default filenames vector */
  165. char **pfnames = fnames, **pxnames = &fnames[1];
  166. char near sig[5];
  167. char near answerbuf[10];
  168.  
  169. min_info info[DIR_BLKSIZ], *pInfo=info;
  170.  
  171. /*---------------------------------------------------------------------------
  172.     unreduce/unshrink/explode/inflate working storage and globals:
  173.   ---------------------------------------------------------------------------*/
  174.  
  175. union work area;              /* see unzip.h for the definition of work */
  176. ulg crc32val;
  177.  
  178. ush near mask_bits[] = {
  179.     0x0000,
  180.     0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
  181.     0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
  182. };
  183.  
  184. /*---------------------------------------------------------------------------
  185.     Input file variables:
  186.   ---------------------------------------------------------------------------*/
  187.  
  188. uch *inbuf, *inptr;             /* input buffer (any size is OK) and pointer */
  189. int incnt;
  190.  
  191. ulg bitbuf;
  192. int bits_left;
  193. boolean zipeof;
  194.  
  195. char *wildzipfn, *zipfn;    /* GRR:  MSWIN:  must nuke any malloc'd zipfn... */
  196.  
  197. int zipfd;                      /* zipfile file handle */
  198. LONGINT ziplen;
  199.  
  200. uch *hold;
  201. char near local_hdr_sig[5];     /* initialize signatures at runtime so unzip */
  202. char near central_hdr_sig[5];   /*  executable won't look like a zipfile */
  203. char near end_central_sig[5];
  204. /* char extd_local_sig[5];  NOT USED YET */
  205.  
  206. cdir_file_hdr crec;             /* used in unzip.c, extract.c, misc.c */
  207. local_file_hdr lrec;            /* used in unzip.c, extract.c */
  208. ecdir_rec ecrec;                /* used in unzip.c, extract.c */
  209. struct stat statbuf;            /* used by main, mapname, check_for_newer */
  210.  
  211. LONGINT cur_zipfile_bufstart;   /* extract_or_test_files, readbuf, ReadByte */
  212. LONGINT extra_bytes = 0;        /* used in unzip.c, misc.c */
  213.  
  214. uch *extra_field = (uch *)NULL; /* used by VMS, Mac and OS/2 versions */
  215.  
  216. #ifdef MACOS
  217.    short  gnVRefNum;
  218.    long  glDirID;
  219.    OSType  gostCreator;
  220.    OSType  gostType;
  221.    boolean  fMacZipped;
  222.    boolean  macflag;
  223.    CursHandle  rghCursor[4];    /* status cursors */
  224.    short  giCursor = 0;
  225. #endif
  226.  
  227. /*---------------------------------------------------------------------------
  228.     Output stream variables:
  229.   ---------------------------------------------------------------------------*/
  230.  
  231. int mem_mode = 0;
  232. int disk_full;
  233. #ifdef SYMLINKS
  234.    int symlnk;
  235. #endif
  236. FILE *outfile;
  237. uch *outbuf;
  238. uch *outptr;
  239. ulg outcnt;                     /* number of chars stored in outbuf */
  240. #ifdef SMALL_MEM
  241.    uch *outbuf2;                /* initialized in main() (never changes) */
  242. #else
  243.    uch *outbuf2 = NULL;         /* malloc'd ONLY if unshrink and -a */
  244. #endif
  245. #ifdef MSWIN
  246.    char *filename;
  247. #else
  248.    char near filename[FILNAMSIZ];
  249. #endif
  250.  
  251. /*---------------------------------------------------------------------------
  252.     unzip.c repeated error messages (we use all of these at least twice)
  253.   ---------------------------------------------------------------------------*/
  254.  
  255. char *EndSigMsg = "\nnote:\
  256.   didn't find end-of-central-dir signature at end of central dir.\n";
  257. char *CentSigMsg =
  258.   "error:  expected central file header signature not found (file #%u).\n";
  259. char *SeekMsg =
  260.   "error [%s]:  attempt to seek before beginning of zipfile\n%s";
  261.  
  262. #ifdef VMS
  263.   char *ReportMsg = "\
  264.   (please check that you have transferred or created the zipfile in the\n\
  265.   appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n";
  266. #else
  267.   char *ReportMsg = "\
  268.   (please check that you have transferred or created the zipfile in the\n\
  269.   appropriate BINARY mode and that you have compiled unzip properly)\n";
  270. #endif
  271.  
  272.  
  273.  
  274.  
  275.  
  276. #ifdef MSWIN
  277. #  include "winsetup.c"   /* duplicates some code in main() */
  278. #else /* !MSWIN */
  279.  
  280. /******************/
  281. /*  Main program  */
  282. /******************/
  283.  
  284. #ifdef THINK_C
  285.  int unzip(argc, argv)
  286. #else
  287.  int main(argc, argv)   /* return PK-type error code (except under VMS) */
  288. #endif
  289.     int argc;
  290.     char *argv[];
  291. {
  292.  
  293. // change by lgk 2/10/94 to get rid of unused variable message
  294. #ifndef NO_ZIPINFO
  295.     char *p;
  296. #endif
  297.  
  298.     int error=FALSE;
  299. #if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
  300.     extern void DebugMalloc(void);
  301.  
  302.  
  303.     atexit(DebugMalloc);
  304. #endif
  305.  
  306. /*---------------------------------------------------------------------------
  307.     Macintosh initialization code.
  308.   ---------------------------------------------------------------------------*/
  309.  
  310. #ifdef MACOS
  311.     int a;
  312.  
  313.     for (a = 0;  a < 4;  ++a)
  314.         rghCursor[a] = GetCursor(a+128);
  315.     giCursor = 0;
  316.  
  317.     aflag=cflag=dflag=fflag=jflag=qflag=tflag=U_flag=uflag=vflag=zflag = 0;
  318.     local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0';
  319. /*  extd_local_sig[1] = '\0';  */
  320.     error = FALSE;
  321.  
  322.     overwrite_none = overwrite_all = force_flag = 0;
  323. #endif /* MACOS */
  324.  
  325. #ifdef MALLOC_WORK
  326.     area.Slide = (uch *)calloc(8193, sizeof(short)+sizeof(char)+sizeof(char));
  327.     area.shrink.Prefix_of = (short *)area.Slide;
  328.     area.shrink.Suffix_of = area.Slide + (sizeof(short)*(HSIZE+1));
  329.     area.shrink.Stack = area.Slide + (sizeof(short) + sizeof(char))*(HSIZE+1);
  330. #endif
  331.  
  332. /*---------------------------------------------------------------------------
  333.     Human68K initialization code.
  334.   ---------------------------------------------------------------------------*/
  335.  
  336. #ifdef __human68k__
  337.     InitTwentyOne();
  338. #endif
  339.  
  340. /*---------------------------------------------------------------------------
  341.     Set signal handler for restoring echo, warn of zipfile corruption, etc.
  342.   ---------------------------------------------------------------------------*/
  343.  
  344.     signal(SIGINT, handler);
  345. #ifdef SIGTERM                 /* some systems really have no SIGTERM */
  346.     signal(SIGTERM, handler);
  347. #endif
  348. #ifdef SIGBUS
  349.     signal(SIGBUS, handler);
  350. #endif
  351. #ifdef SIGSEGV
  352.     signal(SIGSEGV, handler);
  353. #endif
  354.  
  355. /*---------------------------------------------------------------------------
  356.     Debugging info for checking on structure padding:
  357.   ---------------------------------------------------------------------------*/
  358.  
  359. #ifdef DEBUG_STRUC
  360.     printf("local_file_hdr size: %X\n",
  361.            sizeof(local_file_hdr));
  362.     printf("local_byte_hdr size: %X\n",
  363.            sizeof(local_byte_hdr));
  364.     printf("actual size of local headers: %X\n", LREC_SIZE);
  365.  
  366.     printf("central directory header size: %X\n",
  367.            sizeof(cdir_file_hdr));
  368.     printf("central directory byte header size: %X\n",
  369.            sizeof(cdir_byte_hdr));
  370.     printf("actual size of central dir headers: %X\n", CREC_SIZE);
  371.  
  372.     printf("end central dir record size: %X\n",
  373.            sizeof(ecdir_rec));
  374.     printf("end central dir byte record size: %X\n",
  375.            sizeof(ec_byte_rec));
  376.     printf("actual size of end-central-dir record: %X\n", ECREC_SIZE);
  377. #endif /* DEBUG_STRUC */
  378.  
  379. /*---------------------------------------------------------------------------
  380.     First figure out if we're running in UnZip mode or ZipInfo mode, and put
  381.     the appropriate environment-variable options into the queue.  Then rip
  382.     through any command-line options lurking about...
  383.   ---------------------------------------------------------------------------*/
  384.  
  385. #ifdef SFX
  386.     zipfn = argv[0];
  387. #endif
  388.  
  389. #ifndef NO_ZIPINFO
  390.     if ((p = strrchr(argv[0], DIR_END)) == NULL)
  391.         p = argv[0];
  392.     else
  393.         ++p;
  394.  
  395.     if (STRNICMP(p, "zipinfo", 7) == 0 || STRNICMP(p, "ii", 2) == 0 ||
  396.         (argc > 1 && strncmp(argv[1], "-Z", 2) == 0))
  397.     {
  398.         zipinfo_mode = TRUE;
  399.         envargs(&argc, &argv, ENV_ZIPINFO);
  400.         error = zi_opts(&argc, &argv);
  401.     } else
  402. #endif
  403.     {
  404.         zipinfo_mode = FALSE;
  405.         envargs(&argc, &argv, ENV_UNZIP);
  406.         error = uz_opts(&argc, &argv);
  407.     }
  408.  
  409. #ifdef MSDOS
  410.     /* extract MKS extended argument list from environment */
  411.     mksargs(&argc, &argv);
  412. #endif
  413.  
  414. #ifdef SFX
  415.     if (error)
  416. #else
  417.     if ((argc < 0) || error)
  418. #endif
  419.         RETURN(error);
  420.  
  421. /*---------------------------------------------------------------------------
  422.     Now get the zipfile name from the command line and see if it exists as a
  423.     regular (non-directory) file.  If not, append the ".zip" suffix.  We don't
  424.     immediately check to see if this results in a good name, but we will do so
  425.     later.  In the meantime, see if there are any member filespecs on the com-
  426.     mand line, and if so, set the filename pointer to point at them.
  427.   ---------------------------------------------------------------------------*/
  428.  
  429. #ifdef DOS_NT_OS2
  430.     /* convert MSDOS-style directory separators to Unix-style ones for
  431.      * user's convenience (include zipfile name itself)
  432.      */
  433.     pfnames = argv;
  434.     while (*pfnames != NULL) {
  435.         char *q;
  436.  
  437.         for (q = *pfnames;  *q;  ++q)
  438.             if (*q == '\\')
  439.                 *q = '/';
  440.         ++pfnames;
  441.     }
  442. #endif
  443.  
  444.     wildzipfn = *argv++;
  445.  
  446. #ifdef OLD_EXDIR
  447.  
  448.     if (argc > 0) {
  449.         /* -d:  "name/" immediately after zipfile name is a stored directory to
  450.          * be extracted--do NOT treat as directory to which to extract files
  451.          */
  452.         if (extract_flag && !dflag) {
  453.             create_dirs = !fflag;
  454.             if ((error = checkdir(*argv, ROOT)) > 2)  /* mem, or file in way */
  455.                 RETURN(error);
  456.             else if (!error) {   /* it IS extract-to dir, so adjust pointers */
  457.                 ++argv;
  458.                 --argc;
  459.             }
  460.         }
  461.     }
  462.  
  463.     filespecs = argc;
  464.     xfilespecs = 0;
  465.  
  466.     if (argc > 0) {
  467.         char **pp = argv-1;
  468.  
  469.         pfnames = argv;
  470.         while (*++pp)
  471.             if (strcmp(*pp, "-x") == 0) {
  472.                 if (pp > argv) {
  473.                     *pp = 0;           /* terminate pfnames */
  474.                     filespecs = pp - pfnames;
  475.                 } else {
  476.                     pfnames = fnames;  /* defaults */
  477.                     filespecs = 0;
  478.                 }
  479.                 pxnames = pp + 1;      /* excluded-names ptr starts after -x */
  480.                 xfilespecs = argc - filespecs - 1;
  481.                 break;                 /* skip rest of args */
  482.             }
  483.         process_all_files = FALSE;
  484.     } else
  485.         process_all_files = TRUE;       /* for speed */
  486.  
  487. #else /* !OLD_EXDIR */
  488.  
  489.     filespecs = argc;
  490.     xfilespecs = 0;
  491.  
  492.     if (argc > 0) {
  493.         int in_files=FALSE, in_xfiles=FALSE;
  494.         char **pp = argv-1;
  495.  
  496.         process_all_files = FALSE;
  497.         pfnames = argv;
  498.         while (*++pp) {
  499.             Trace((stderr, "pp - argv = %d\n", pp-argv));
  500.             if (!dflag && strcmp(*pp, "-d") == 0) {
  501.                 dflag = TRUE;
  502.                 if (in_files) {      /* ... zipfile ... -d exdir ... */
  503.                     *pp = 0;                    /* terminate pfnames */
  504.                     filespecs = pp - pfnames;
  505.                     in_files = FALSE;
  506.                 } else if (in_xfiles) {
  507.                     *pp = 0;                    /* terminate pxnames */
  508.                     xfilespecs = pp - pxnames;
  509.                     /* "... -x xlist -d exdir":  nothing left */
  510.                 }
  511.                 if (*++pp) {
  512.                     if (extract_flag) {
  513.                         create_dirs = !fflag;
  514.                         if ((error = checkdir(*pp, ROOT)) > 2)
  515.                             RETURN(error);   /* out of memory, or file in way */
  516.                     } else
  517.                         fprintf(stderr,
  518.                           "caution:  not extracting; -d ignored\n");
  519.                 } else {
  520.                     fprintf(stderr, "error:  must specify directory to which to\
  521.  extract with -d option\n");
  522.                     break;   /* no arguments left */
  523.                 }
  524.                 if (pp == argv+1)   /* ... zipfile -d exdir ... */
  525.                     if (pp[1]) {
  526.                         pfnames = pp + 1;  /* argv+2 */
  527.                         filespecs = argc - (pfnames-argv);  /* for now... */
  528.                     } else {
  529.                         process_all_files = TRUE;
  530.                         pfnames = fnames;  /* GRR: necessary? */
  531.                         filespecs = 0;     /* GRR: necessary? */
  532.                         break;
  533.                     }
  534.             } else if (!in_xfiles) {
  535.                 if (strcmp(*pp, "-x") == 0) {
  536.                     in_xfiles = TRUE;
  537.                     if (pp == argv || (pp == argv+2 && dflag)) {
  538.                         pfnames = fnames;  /* defaults */
  539.                         filespecs = 0;
  540.                     } else if (in_files) {
  541.                         *pp = 0;                   /* terminate pfnames */
  542.                         filespecs = pp - pfnames;  /* adjust count */
  543.                         in_files = FALSE;
  544.                     }
  545.                     pxnames = pp + 1;  /* excluded-names ptr starts after -x */
  546.                     xfilespecs = argc - (pxnames-argv);  /* anything left... */
  547.                 } else
  548.                     in_files = TRUE;
  549.             }
  550.         }
  551.     } else
  552.         process_all_files = TRUE;      /* for speed */
  553.  
  554. #endif /* ?OLD_EXDIR */
  555.  
  556. /*---------------------------------------------------------------------------
  557.     Okey dokey, we have everything we need to get started.  Let's roll.
  558.   ---------------------------------------------------------------------------*/
  559.  
  560.     inbuf = (uch *)malloc(INBUFSIZ + 4);    /* 4 extra for hold[] (below) */
  561.     outbuf = (uch *)malloc(OUTBUFSIZ + 1);  /* 1 extra for string termin. */
  562.  
  563.     if ((inbuf == (uch *)NULL) || (outbuf == (uch *)NULL)) {
  564.         fprintf(stderr, "error:  can't allocate unzip buffers\n");
  565.         RETURN(PK_MEM);
  566.     }
  567.     hold = inbuf + INBUFSIZ;     /* to check for boundary-spanning signatures */
  568. #ifdef SMALL_MEM
  569.     outbuf2 = outbuf+RAWBUFSIZ;  /* never changes */
  570. #endif
  571.  
  572.     RETURN(process_zipfiles());  /* keep passing errors back... */
  573.  
  574. } /* end main() */
  575.  
  576.  
  577.  
  578.  
  579.  
  580. /************************/
  581. /*  Function uz_opts()  */
  582. /************************/
  583.  
  584. int uz_opts(pargc, pargv)
  585.     int *pargc;
  586.     char ***pargv;
  587. {
  588.     char **argv, *s;
  589.     int argc, c, error=FALSE, negative=0;
  590.  
  591.  
  592.     argc = *pargc;
  593.     argv = *pargv;
  594.  
  595.     while (--argc > 0 && (*++argv)[0] == '-') {
  596.         s = argv[0] + 1;
  597.         while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
  598.             switch (c) {
  599.                 case ('-'):
  600.                     ++negative;
  601.                     break;
  602.                 case ('a'):
  603.                     if (negative) {
  604.                         aflag = MAX(aflag-negative,0);
  605.                         negative = 0;
  606.                     } else
  607.                         ++aflag;
  608.                     break;
  609.                 case ('b'):
  610.                     if (negative)
  611.                         negative = 0;   /* do nothing:  "-b" is default */
  612.                     else
  613.                         aflag = 0;
  614.                     break;
  615.                 case ('c'):
  616.                     if (negative) {
  617.                         cflag = FALSE, negative = 0;
  618. #ifdef NATIVE
  619.                         aflag = 0;
  620. #endif
  621.                     } else {
  622.                         cflag = TRUE;
  623. #ifdef NATIVE
  624.                         aflag = 2;  /* so you can read it on the screen */
  625. #endif
  626.                     }
  627.                     break;
  628.                 case ('d'):  /* arg after zipfn is stored dir, not extract-to */
  629. #ifdef OLD_EXDIR
  630.                     if (negative)
  631.                         dflag = FALSE, negative = 0;
  632.                     else
  633.                         dflag = TRUE;
  634. #endif
  635.                     break;
  636.                 case ('e'):    /* just ignore -e, -x options (extract) */
  637.                     break;
  638.                 case ('f'):    /* "freshen" (extract only newer files) */
  639.                     if (negative)
  640.                         fflag = uflag = FALSE, negative = 0;
  641.                     else
  642.                         fflag = uflag = TRUE;
  643.                     break;
  644.                 case ('j'):    /* junk pathnames/directory structure */
  645.                     if (negative)
  646.                         jflag = FALSE, negative = 0;
  647.                     else
  648.                         jflag = TRUE;
  649.                     break;
  650.                 case ('l'):
  651.                     if (negative) {
  652.                         vflag = MAX(vflag-negative,0);
  653.                         negative = 0;
  654.                     } else
  655.                         ++vflag;
  656.                     break;
  657.                 case ('n'):    /* don't overwrite any files */
  658.                     if (negative)
  659.                         overwrite_none = FALSE, negative = 0;
  660.                     else
  661.                         overwrite_none = TRUE;
  662.                     break;
  663.                 case ('o'):    /* OK to overwrite files without prompting */
  664.                     if (negative) {
  665.                         overwrite_all = MAX(overwrite_all-negative,0);
  666.                         force_flag = MAX(force_flag-negative,0);
  667.                         negative = 0;
  668.                     } else {
  669.                         ++overwrite_all;
  670.                         ++force_flag;  /* (share -o for now) force to cont. */
  671.                     }
  672.                     break;
  673.                 case ('p'):    /* pipes:  stdout, no translation, no messages */
  674.                     if (negative) {
  675.                         cflag = FALSE;
  676.                         qflag = MAX(qflag-999,0);
  677.                         negative = 0;
  678.                     } else {
  679.                         aflag = 0;
  680.                         cflag = TRUE;
  681.                         qflag += 999;
  682.                     }
  683.                     break;
  684.                 case ('q'):    /* quiet:  fewer comments/messages */
  685.                     if (negative) {
  686.                         qflag = MAX(qflag-negative,0);
  687.                         negative = 0;
  688.                     } else
  689.                         ++qflag;
  690.                     break;
  691. #ifdef DOS_NT_OS2
  692.                 case ('s'):    /* spaces in filenames:  allow by default */
  693.                     if (negative)
  694.                         sflag = FALSE, negative = 0;
  695.                     else
  696.                         sflag = TRUE;
  697.                     break;
  698. #endif
  699.                 case ('t'):
  700.                     if (negative)
  701.                         tflag = FALSE, negative = 0;
  702.                     else
  703.                         tflag = TRUE;
  704.                     break;
  705.                 case ('U'):    /* allow Uppercase (don't make all lowercase) */
  706.                     if (negative)
  707.                         U_flag = FALSE, negative = 0;
  708.                     else
  709.                         U_flag = TRUE;
  710.                     break;
  711.                 case ('u'):    /* update (extract only new and newer files) */
  712.                     if (negative)
  713.                         uflag = FALSE, negative = 0;
  714.                     else
  715.                         uflag = TRUE;
  716.                     break;
  717.                 case ('V'):    /* Version (retain VMS/DEC-20 file versions) */
  718.                     if (negative)
  719.                         V_flag = FALSE, negative = 0;
  720.                     else
  721.                         V_flag = TRUE;
  722.                     break;
  723.                 case ('v'):    /* verbose */
  724.                     if (negative) {
  725.                         vflag = MAX(vflag-negative,0);
  726.                         negative = 0;
  727.                     } else if (vflag)
  728.                         ++vflag;
  729.                     else
  730.                         vflag = 2;
  731.                     break;
  732. #ifdef VMS
  733.                 case ('X'):   /* restore owner/protection info (need privs?) */
  734.                     if (negative)
  735.                         secinf = FALSE, negative = 0;
  736.                     else
  737.                         secinf = TRUE;
  738.                     break;
  739. #endif /* VMS */
  740.                 case ('x'):    /* extract:  default */
  741.                     break;
  742.                 case ('z'):    /* display only the archive comment */
  743.                     if (negative) {
  744.                         zflag -= negative;
  745.                         negative = 0;
  746.                     } else
  747.                         ++zflag;
  748.                     break;
  749. #ifdef DOS_NT_OS2
  750.                 case ('$'):
  751.                     if (negative) {
  752.                         volflag = MAX(volflag-negative,0);
  753.                         negative = 0;
  754.                     } else
  755.                         ++volflag;
  756.                     break;
  757. #endif
  758.                 default:
  759.                     error = TRUE;
  760.                     break;
  761.  
  762.             } /* end switch */
  763.         } /* end while (not end of argument string) */
  764.     } /* end while (not done with switches) */
  765.  
  766. /*---------------------------------------------------------------------------
  767.     Check for nonsensical combinations of options.  [Isn't the -a option use-
  768.     ful when listing the directory (i.e., for reading zipfile comments)?  It
  769.     is only a modifier, so perhaps it should not be included in the test.]
  770.   ---------------------------------------------------------------------------*/
  771.  
  772.     if ((cflag && tflag) || (cflag && uflag) || (cflag && vflag) ||
  773.         (tflag && uflag) || (tflag && vflag) || (uflag && vflag) ||
  774.         (fflag && overwrite_none)) {
  775.         fprintf(stderr, "error:\
  776.   -fn or any combination of -c, -l, -p, -t, -u and -v options invalid\n");
  777.         error = TRUE;
  778.     }
  779.     if (aflag > 2)
  780.         aflag = 2;
  781. #if 0
  782.     if ((aflag && tflag) || (aflag && vflag))   /* -a makes no sense */
  783.         aflag = 0;
  784. #endif
  785.     if (overwrite_all && overwrite_none) {
  786.         fprintf(stderr, "caution:  both -n and -o specified; ignoring -o\n");
  787.         overwrite_all = FALSE;
  788.     }
  789.  
  790. #ifdef SFX
  791.     if (error)
  792. #else
  793.     if ((argc-- == 0) || error)
  794. #endif
  795.     {
  796.         *pargc = argc;
  797.         *pargv = argv;
  798.         return usage(error);
  799.     }
  800.  
  801.     if (cflag || tflag || vflag)
  802.         extract_flag = FALSE;
  803.     else
  804.         extract_flag = TRUE;
  805.  
  806.     *pargc = argc;
  807.     *pargv = argv;
  808.     return 0;
  809.  
  810. } /* end function uz_opts() */
  811.  
  812.  
  813.  
  814.  
  815.  
  816. /**********************/
  817. /*  Function usage()  */
  818. /**********************/
  819.  
  820. #ifdef SFX
  821.  
  822. int usage(error)   /* return PK-type error code */
  823.     int error;
  824. {
  825.     FILE *usagefp;
  826.  
  827.     if (error)
  828.         usagefp = (FILE *)stderr;
  829.     else
  830.         usagefp = (FILE *)stdout;
  831.  
  832.     fprintf(usagefp, "\
  833. UnZipSFX %s, by Info-ZIP (zip-bugs@wkuvx1.wku.edu).\n\n",
  834.       UZ_VERSION);
  835. #ifndef RELEASE
  836.     fprintf(usagefp, "\
  837.     THIS IS STILL A BETA VERSION OF UNZIPSFX -- DO NOT DISTRIBUTE.\n\n");
  838. #endif
  839.  
  840.     if (error)
  841.         return PK_PARAM;
  842.     else
  843.         return PK_COOL;     /* just wanted usage screen: no error */
  844.  
  845. } /* end function usage() */
  846.  
  847.  
  848.  
  849.  
  850.  
  851. #else /* !SFX */
  852.  
  853. int usage(error)   /* return PK-type error code */
  854.     int error;
  855. {
  856. #ifdef VMS
  857. #  define QUOT '\"'
  858. #  define QUOTS "\""
  859. #  define EXAMPLE2 "vms.c"
  860. #  define EXAMPLE1 \
  861. "unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS"
  862. #else
  863. #  define QUOT ' '
  864. #  define QUOTS ""
  865. #  define EXAMPLE2 "ReadMe"
  866. #  define EXAMPLE1 \
  867. "unzip -p foo | more  => send contents of foo.zip via pipe into program more"
  868. #endif
  869.  
  870. #ifdef DOS_NT_OS2
  871.     char *loc_str = " -$  label removables (-$$ => fixed disks)";
  872.     char *loc2str = "\
  873.                                              -s  spaces in filenames => '_'\n";
  874. #else /* !DOS_NT_OS2 */
  875. #ifdef VMS
  876.     char *loc_str = "\"-X\" restore owner/protection info";
  877.     char *loc2str = "\n";
  878. #else
  879.     char *loc_str = "";   /* Unix, Amiga, Mac, etc. */
  880.  /* char *loc_str = " -X  restore UID/GID info";    Unix version, in 5.2 */
  881.     char *loc2str = "";
  882. #endif
  883. #endif /* ?DOS_NT_OS2 */
  884.  
  885.     FILE *usagefp;
  886.  
  887.  
  888. /*---------------------------------------------------------------------------
  889.     If user requested usage, send it to stdout; else send to stderr.
  890.   ---------------------------------------------------------------------------*/
  891.  
  892.     if (error)
  893.         usagefp = (FILE *)stderr;
  894.     else
  895.         usagefp = (FILE *)stdout;
  896.  
  897. /*---------------------------------------------------------------------------
  898.     Print either ZipInfo usage or UnZip usage, depending on incantation.
  899.     (Strings must be no longer than 512 bytes for Turbo C, apparently.)
  900.   ---------------------------------------------------------------------------*/
  901.  
  902.     if (zipinfo_mode) {
  903.  
  904. #ifndef NO_ZIPINFO
  905.  
  906.         fprintf(usagefp, "\
  907. ZipInfo %s, by Newtware and the fine folks at Info-ZIP.\n\
  908. \n\
  909. List name, date/time, attribute, size, compression method, etc., about files\n\
  910. in list (excluding those in xlist) contained in the specified .zip archive(s).\
  911. \n\"file[.zip]\" may be a wildcard name containing *, ?, [] (e.g., \"[a-j]*\
  912. .zip\").\n\n\
  913.    usage:  zipinfo [-12smlvhtz] file[.zip] [list...] [-x xlist...]\n\
  914.       or:  unzip %s-Z%s [-12smlvhtz] file[.zip] [list...] [-x xlist...]\n",
  915.           ZI_VERSION, QUOTS,QUOTS);
  916.         fprintf(usagefp, "\nmain\
  917.  listing-format options:             -s  short Unix \"ls -l\" format (def.)\n\
  918.   -1  filenames ONLY, one per line       -m  medium Unix \"ls -l\" format\n\
  919.   -2  just filenames but allow -h/-t/-z  -l  long Unix \"ls -l\" format\n\
  920.                                          -v  verbose, multi-page format\n\
  921. miscellaneous options:\n  \
  922. -h  print header line      -t  print totals for files listed or for all files\n\
  923.   -z  print zipfile comment  -x  exclude filenames that follow from listing\n");
  924. /* -p  disable automatic \"more\" function (for pipes) [not implemented]\n"); */
  925. #ifdef VMS
  926.         fprintf(usagefp, "\nRemember that non-lowercase filespecs must be\
  927.  quoted in VMS (e.g., \"Makefile\").\n");
  928. #endif
  929.  
  930. #endif /* !NO_ZIPINFO */
  931.  
  932.     } else {   /* UnZip mode */
  933.  
  934.         fprintf(usagefp, "\
  935. UnZip %s, by Info-ZIP.  Portions (c) 1989 by S. H. Smith.\n\
  936. Send bug reports to authors at zip-bugs@wkuvx1.wku.edu; see README for details.\
  937. \n\n", UZ_VERSION);
  938. #ifndef RELEASE
  939.         fprintf(usagefp, "\
  940.         THIS IS STILL A BETA VERSION OF UNZIP -- DO NOT DISTRIBUTE.\n\n");
  941. #endif
  942.         fprintf(usagefp, "\
  943. Usage: unzip %s[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]\n \
  944.  Default action is to extract files in list, except those in xlist, to exdir;\n\
  945.   file[.zip] may be a wildcard.  %s\n\n",
  946. #ifdef NO_ZIPINFO
  947.           "", "(ZipInfo mode is disabled in this version.)");
  948. #else
  949. #ifdef VMS
  950.           "[-Z] ", "\"-Z\" => ZipInfo mode (`unzip \"-Z\"' for usage).");
  951. #else
  952.           "[-Z] ", "-Z => ZipInfo mode (\"unzip -Z\" for usage).");
  953. #endif
  954. #endif /* ?NO_ZIPINFO */
  955.  
  956.         fprintf(usagefp, "\
  957.   -c  extract files to stdout/screen (CRT)   -l  list files (short format)\n\
  958.   -p  extract files to pipe, no messages     -v  list files (verbose format)\n\
  959.   -f  freshen existing files, create none    -t  test compressed archive data\n\
  960.   -u  update files, create if necessary      -z  display archive comment\n\
  961.   -x  exclude files which follow (in xlist)  -d  extract files into exdir\n\n");
  962.  
  963.         fprintf(usagefp, "\
  964. modifiers:                                   -q  quiet mode (-qq => quieter)\n\
  965.   -n  never overwrite existing files         -a  auto-convert any text files\n\
  966.   -o  overwrite files WITHOUT prompting      -aa treat ALL files as text\n\
  967.   -j  junk paths (don't make directories)   %c-U%c don't make names lowercase\n\
  968.  %-42s %c-V%c retain VMS version numbers\n%s",
  969.           QUOT,QUOT, loc_str, QUOT,QUOT, loc2str);
  970.  
  971.         fprintf(usagefp, "\
  972. Examples (see unzip.doc for more info):\n\
  973.   unzip data1 -x joe   => extract all files except joe from zipfile data1.zip\n\
  974.   %s\n\
  975.   unzip -fo foo %-6s => quietly replace existing %s if archive file newer\n",
  976.           EXAMPLE1, EXAMPLE2,EXAMPLE2);
  977.  
  978.     }
  979.  
  980.     if (error)
  981.         return PK_PARAM;
  982.     else
  983.         return PK_COOL;     /* just wanted usage screen: no error */
  984.  
  985. } /* end function usage() */
  986.  
  987. #endif /* ?SFX */
  988. #endif /* ?MSWIN */
  989.  
  990.  
  991.  
  992.  
  993. /*********************************/
  994. /*  Function process_zipfiles()  */
  995. /*********************************/
  996.  
  997. int process_zipfiles()    /* return PK-type error code */
  998. {
  999.     char *lastzipfn = NULL;
  1000.     int error=0, error_in_archive=0;
  1001.     int num_win_files, num_lose_files, num_warn_files;
  1002.     int num_miss_dirs, num_miss_files;
  1003.  
  1004.  
  1005. /*---------------------------------------------------------------------------
  1006.     Start by constructing the various PK signature strings.
  1007.   ---------------------------------------------------------------------------*/
  1008.  
  1009.     local_hdr_sig[0]  /* = extd_local_sig[0] */  = '\120';   /* ASCII 'P', */
  1010.     central_hdr_sig[0] = end_central_sig[0] = '\120';        /* not EBCDIC */
  1011.  
  1012.     strcpy(local_hdr_sig+1, LOCAL_HDR_SIG);
  1013.     strcpy(central_hdr_sig+1, CENTRAL_HDR_SIG);
  1014.     strcpy(end_central_sig+1, END_CENTRAL_SIG);
  1015. /*  strcpy(extd_local_sig+1, EXTD_LOCAL_SIG);   still to be used in multi? */
  1016.  
  1017. /*---------------------------------------------------------------------------
  1018.     Match (possible) wildcard zipfile specification with existing files and
  1019.     attempt to process each.  If no hits, try again after appending ".zip"
  1020.     suffix.  If still no luck, give up.
  1021.   ---------------------------------------------------------------------------*/
  1022.  
  1023. #ifdef SFX
  1024.     if ((error = do_seekable(0)) != IZ_DIR && error > error_in_archive)
  1025.         error_in_archive = error;
  1026.  
  1027. #else /* !SFX */
  1028.     num_win_files = num_lose_files = num_warn_files = 0;
  1029.     num_miss_dirs = num_miss_files = 0;
  1030.  
  1031.     while ((zipfn = do_wild(wildzipfn)) != NULL) {
  1032.         Trace((stderr, "do_wild( %s ) returns %s\n", wildzipfn, zipfn));
  1033.  
  1034.         lastzipfn = zipfn;
  1035.  
  1036.         if (!qflag  &&  error != PK_NOZIP  &&
  1037.             (num_win_files+num_lose_files+num_warn_files+num_miss_files) > 0)
  1038.             printf("\n");
  1039.         FFLUSH(stdout);
  1040.  
  1041.         if ((error = do_seekable(0)) == PK_WARN)
  1042.             ++num_warn_files;
  1043.         else if (error == IZ_DIR)
  1044.             ++num_miss_dirs;
  1045.         else if (error == PK_NOZIP)
  1046.             ++num_miss_files;
  1047.         else if (error)
  1048.             ++num_lose_files;
  1049.         else
  1050.             ++num_win_files;
  1051.  
  1052.         if (error != IZ_DIR && error > error_in_archive)
  1053.             error_in_archive = error;
  1054.         Trace((stderr, "do_seekable(0) returns %d\n", error));
  1055.  
  1056.     } /* end while-loop (wildcard zipfiles) */
  1057.  
  1058.     if ((num_win_files + num_warn_files + num_lose_files) == 0  &&
  1059.         (num_miss_dirs + num_miss_files) == 1  &&  lastzipfn != NULL)
  1060.     {
  1061.         num_miss_dirs = num_miss_files = 0;
  1062.         if (error_in_archive == PK_NOZIP)
  1063.             error_in_archive = PK_COOL;
  1064.         strcat((zipfn = lastzipfn), ZSUFX);
  1065.  
  1066.         if ((error = do_seekable(1)) == PK_WARN)
  1067.             ++num_warn_files;
  1068.         else if (error == IZ_DIR)
  1069.             ++num_miss_dirs;
  1070.         else if (error == PK_NOZIP)
  1071.             /* if increment again => bug: "1 file had no zipfile directory." */
  1072.             /* ++num_miss_files */ ;
  1073.         else if (error)
  1074.             ++num_lose_files;
  1075.         else
  1076.             ++num_win_files;
  1077.  
  1078.         if (error > error_in_archive)
  1079.             error_in_archive = error;
  1080.         Trace((stderr, "do_seekable(1) returns %d\n", error));
  1081.     }
  1082. #endif /* ?SFX */
  1083.  
  1084.     FFLUSH(stdout);
  1085.     FFLUSH(stderr);
  1086.  
  1087. #ifndef SFX
  1088.     if (num_miss_dirs + num_miss_files + num_lose_files + num_warn_files > 0
  1089.         || num_win_files != 1)
  1090.         fprintf(stderr, "\n");
  1091.     if ((num_win_files > 1) || (num_win_files == 1 &&
  1092.         num_miss_dirs + num_miss_files + num_lose_files + num_warn_files > 0))
  1093.         fprintf(stderr, "%d archive%s successfully processed.\n",
  1094.           num_win_files, (num_win_files == 1)? " was" : "s were");
  1095.     if (num_warn_files > 0)
  1096.         fprintf(stderr, "%d archive%s had warnings but no fatal errors.\n",
  1097.           num_warn_files, (num_warn_files == 1)? "" : "s");
  1098.     if (num_lose_files > 0)
  1099.         fprintf(stderr, "%d archive%s had fatal errors.\n",
  1100.           num_lose_files, (num_lose_files == 1)? "" : "s");
  1101.     if (num_miss_files > 0)
  1102.         fprintf(stderr, "%d file%s had no zipfile directory.\n",
  1103.           num_miss_files, (num_miss_files == 1)? "" : "s");
  1104.     if (num_miss_dirs == 1)
  1105.         fprintf(stderr, "1 \"zipfile\" was a directory.\n");
  1106.     else if (num_miss_dirs > 0)
  1107.         fprintf(stderr, "%d \"zipfiles\" were directories.\n", num_miss_dirs);
  1108.     if (num_win_files + num_lose_files + num_warn_files == 0)
  1109.         fprintf(stderr, "No zipfiles found.\n");
  1110. #endif /* !SFX */
  1111.  
  1112.     /* free allocated memory */
  1113.     inflate_free();
  1114.     checkdir((char *)NULL, END);
  1115. #ifndef SMALL_MEM
  1116.     if (outbuf2)
  1117.         free(outbuf2);   /* malloc'd ONLY if unshrink and -a */
  1118. #endif
  1119.     free(outbuf);
  1120.     free(inbuf);
  1121.  
  1122.     return error_in_archive;
  1123.  
  1124. } /* end function process_zipfiles() */
  1125.  
  1126.  
  1127.  
  1128.  
  1129.  
  1130. /****************************/
  1131. /*  Function do_seekable()  */
  1132. /****************************/
  1133.  
  1134. int do_seekable(lastchance)    /* return PK-type error code */
  1135.     int lastchance;
  1136. {
  1137.     int error=0, error_in_archive, maybe_exe=FALSE;
  1138.     static int no_ecrec = FALSE;
  1139.  
  1140.  
  1141. /*---------------------------------------------------------------------------
  1142.     Open the zipfile for reading in BINARY mode to prevent CR/LF translation,
  1143.     which would corrupt the bit streams.
  1144.   ---------------------------------------------------------------------------*/
  1145.  
  1146.     if (SSTAT(zipfn, &statbuf) || (error = S_ISDIR(statbuf.st_mode)) != 0) {
  1147.         if (lastchance)
  1148.             if (no_ecrec)
  1149.                 fprintf(stderr, "%s:  can't find zipfile directory in %s,\n\
  1150.         %sand can't find %s, period.\n", zipinfo_mode? "zipinfo" : "unzip",
  1151.                   wildzipfn, zipinfo_mode? "  " : "", zipfn);
  1152.             else
  1153.                 fprintf(stderr,
  1154.                   "%s:  can't find either %s or %s, so there.\n",
  1155.                   zipinfo_mode? "zipinfo" : "unzip", wildzipfn, zipfn);
  1156.         return error? IZ_DIR : PK_NOZIP;
  1157.     }
  1158.     ziplen = statbuf.st_size;
  1159.  
  1160. #if defined(UNIX) || defined(DOS_NT_OS2)  /* no extension on Unix exec's: */
  1161.     if (statbuf.st_mode & S_IEXEC)      /* might find zip, not zip.zip; etc. */
  1162.         maybe_exe = TRUE;               /* (for other OS's, some executables */
  1163. #endif                                  /* can be self-extracting archives) */
  1164.  
  1165. #ifdef VMS
  1166.     if (check_format())      /* check for variable-length format */
  1167.         return PK_ERR;
  1168. #endif
  1169.  
  1170.     if (open_input_file())   /* this should never happen, given */
  1171.         return PK_NOZIP;     /*  the stat() test above, but... */
  1172.  
  1173. /*---------------------------------------------------------------------------
  1174.     Find and process the end-of-central-directory header.  UnZip need only
  1175.     check last 65557 bytes of zipfile:  comment may be up to 65535, end-of-
  1176.     central-directory record is 18 bytes, and signature itself is 4 bytes;
  1177.     add some to allow for appended garbage.  Since ZipInfo is often used as
  1178.     a debugging tool, search the whole zipfile if zipinfo_mode is true.
  1179.   ---------------------------------------------------------------------------*/
  1180.  
  1181.     cur_zipfile_bufstart = 0;
  1182.     inptr = inbuf;
  1183.  
  1184.     if (!qflag && !zipinfo_mode)
  1185.         printf("Archive:  %s\n", zipfn);
  1186.  
  1187.     if ((
  1188. #ifndef NO_ZIPINFO
  1189.          zipinfo_mode &&
  1190.           ((error_in_archive = find_end_central_dir(ziplen)) != 0 ||
  1191.           (error_in_archive = zi_end_central()) > PK_WARN))
  1192.         || (!zipinfo_mode &&
  1193. #endif
  1194.           ((error_in_archive = find_end_central_dir(MIN(ziplen,66000L))) != 0 ||
  1195.           (error_in_archive = uz_end_central()) > PK_WARN)))
  1196.     {
  1197.         close(zipfd);
  1198. #ifdef SFX
  1199.         return error_in_archive;
  1200. #else
  1201.         if (maybe_exe)
  1202.             fprintf(stderr, "note:  %s may be an executable, not an archive\n",
  1203.               zipfn);
  1204.         if (lastchance)
  1205.             return error_in_archive;
  1206.         else {
  1207.             no_ecrec = TRUE;    /* assume we found wrong file:  e.g., */
  1208.             return PK_NOZIP;    /*  unzip instead of unzip.zip */
  1209.         }
  1210. #endif /* ?SFX */
  1211.     }
  1212.  
  1213.     if ((zflag > 0) && !zipinfo_mode) {   /* in unzip, zflag = comment ONLY */
  1214.         close(zipfd);
  1215.         return error_in_archive;
  1216.     }
  1217.  
  1218. /*---------------------------------------------------------------------------
  1219.     Test the end-of-central-directory info for incompatibilities (multi-disk
  1220.     archives) or inconsistencies (missing or extra bytes in zipfile).
  1221.   ---------------------------------------------------------------------------*/
  1222.  
  1223.     error = !zipinfo_mode && (ecrec.number_this_disk == 1) &&
  1224.             (ecrec.num_disk_with_start_central_dir == 1);
  1225.  
  1226.     if (zipinfo_mode &&
  1227.         ecrec.number_this_disk != ecrec.num_disk_with_start_central_dir)
  1228.     {
  1229.         fprintf(stderr, "\n\
  1230.      Zipfile is part of a multi-disk archive, and this is not the disk on\n\
  1231.      which the central zipfile directory begins.\n");
  1232.         error_in_archive = PK_FIND;
  1233.  
  1234.     } else if (!zipinfo_mode && !error && ecrec.number_this_disk != 0) {
  1235.  
  1236.         fprintf(stderr, "\nerror [%s]:  zipfile is part of multi-disk archive\n\
  1237.   (sorry, not yet supported).\n", zipfn);
  1238.         error_in_archive = PK_FIND;
  1239.  
  1240.     } else {   /* this is a (relatively) normal zipfile:  process normally */
  1241.  
  1242.         if (error) {
  1243.             fprintf(stderr, "\n\
  1244.      Warning:  zipfile claims to be second disk of a two-part archive;\n\
  1245.      attempting to process anyway.  If no further errors occur, this\n\
  1246.      archive was probably created by PAK v2.51 or earlier.  This bug\n\
  1247.      was reported to NoGate in March 1991 and was supposed to have been\n\
  1248.      fixed by mid-1991; as of mid-1992 it still hadn't been.  (If fur-\n\
  1249.      ther errors do occur, archive was probably created by PKZIP 2.04c\n\
  1250.      or later; UnZip does not yet support multi-part archives.)\n\n");
  1251.             error_in_archive = PK_WARN;
  1252.         }
  1253.         if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < (LONGINT)0) {
  1254.             fprintf(stderr, "error [%s]:  missing %ld bytes in zipfile\n\
  1255.   (attempting to process anyway)\n", zipfn, (long)(-extra_bytes));
  1256.             error_in_archive = PK_ERR;
  1257.         } else if (extra_bytes > 0) {
  1258.             if ((ecrec.offset_start_central_directory == 0) &&
  1259.                 (ecrec.size_central_directory != 0))   /* zip 1.5 -go bug */
  1260.             {
  1261.                 fprintf(stderr, "error [%s]:  NULL central directory offset\n\
  1262.   (attempting to process anyway)\n", zipfn);
  1263.                 ecrec.offset_start_central_directory = extra_bytes;
  1264.                 extra_bytes = 0;
  1265.                 error_in_archive = PK_ERR;
  1266.             } else {
  1267. #ifndef SFX
  1268.                 fprintf(stderr, "warning [%s]:  extra %ld bytes at beginning\
  1269.  or within zipfile\n  (attempting to process anyway)\n", zipfn,
  1270.                   (long)extra_bytes);
  1271.                 error_in_archive = PK_WARN;
  1272. #endif
  1273.             }
  1274.         }
  1275.  
  1276.     /*-----------------------------------------------------------------------
  1277.         Check for empty zipfile and exit now if so.
  1278.       -----------------------------------------------------------------------*/
  1279.  
  1280.         if (expect_ecrec_offset == 0L  &&  ecrec.size_central_directory == 0) {
  1281.             if (zipinfo_mode)
  1282.                 printf("%sEmpty zipfile.\n", lflag>9 ? "\n  " : "");
  1283.             else
  1284.                 fprintf(stderr, "warning [%s]:  zipfile is empty\n", zipfn);
  1285.             close(zipfd);
  1286.             return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN;
  1287.         }
  1288.  
  1289.     /*-----------------------------------------------------------------------
  1290.         Compensate for missing or extra bytes, and seek to where the start
  1291.         of central directory should be.  If header not found, uncompensate
  1292.         and try again (necessary for at least some Atari archives created
  1293.         with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
  1294.       -----------------------------------------------------------------------*/
  1295.  
  1296.         LSEEK( ecrec.offset_start_central_directory )
  1297.         if ((error = readbuf(sig, 4)) < 0) {
  1298.             close(zipfd);
  1299.             return PK_ERR;  /* file may be locked, or possibly disk error(?) */
  1300.         }
  1301.         if ((error == 0) || strncmp(sig, central_hdr_sig, 4)) {
  1302.             long tmp = extra_bytes;
  1303.  
  1304.             extra_bytes = 0;
  1305.             LSEEK( ecrec.offset_start_central_directory )
  1306.             if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
  1307.                 fprintf(stderr,
  1308.                   "error [%s]:  start of central directory not found;\n\
  1309.   zipfile corrupt.\n%s", zipfn, ReportMsg);
  1310.                 close(zipfd);
  1311.                 return PK_BADERR;
  1312.             }
  1313.             fprintf(stderr,
  1314.               "error [%s]:  reported length of central directory is\n\
  1315.   %ld bytes too long (Atari STZIP zipfile?  J.H.Holm ZIPSPLIT 1.1\n\
  1316.   zipfile?).  Compensating...\n", zipfn, -tmp);
  1317.             error_in_archive = PK_ERR;
  1318.         }
  1319.  
  1320.     /*-----------------------------------------------------------------------
  1321.         Seek to the start of the central directory one last time, since we
  1322.         have just read the first entry's signature bytes; then list, extract
  1323.         or test member files as instructed, and close the zipfile.
  1324.       -----------------------------------------------------------------------*/
  1325.  
  1326.         Trace((stderr, "about to extract/list files (error = %d)\n",
  1327.           error_in_archive));
  1328.  
  1329.         LSEEK( ecrec.offset_start_central_directory )
  1330.  
  1331. #ifndef NO_ZIPINFO
  1332.         if (zipinfo_mode) {
  1333.             error = zipinfo();                     /* ZIPINFO 'EM */
  1334.             if (lflag > 9)
  1335.                 printf("\n");
  1336.         } else
  1337. #endif
  1338.             if (vflag)
  1339.                 error = list_files();              /* LIST 'EM */
  1340.             else
  1341.                 error = extract_or_test_files();   /* EXTRACT OR TEST 'EM */
  1342.  
  1343.         Trace((stderr, "done with extract/list files (error = %d)\n", error));
  1344.  
  1345.         if (error > error_in_archive)   /* don't overwrite stronger error */
  1346.             error_in_archive = error;   /*  with (for example) a warning */
  1347.     }
  1348.  
  1349.     close(zipfd);
  1350.     return error_in_archive;
  1351.  
  1352. } /* end function do_seekable() */
  1353.  
  1354.  
  1355.  
  1356.  
  1357.  
  1358. /*****************************/
  1359. /* Function uz_end_central() */
  1360. /*****************************/
  1361.  
  1362. int uz_end_central()    /* return PK-type error code */
  1363. {
  1364.     int error = PK_COOL;
  1365.  
  1366.  
  1367. /*---------------------------------------------------------------------------
  1368.     Get the zipfile comment (up to 64KB long), if any, and print it out.
  1369.     Then position the file pointer to the beginning of the central directory
  1370.     and fill buffer.
  1371.   ---------------------------------------------------------------------------*/
  1372.  
  1373. #ifdef MSWIN
  1374.     cchComment = ecrec.zipfile_comment_length; /* save for comment button */
  1375.     if (ecrec.zipfile_comment_length && (zflag > 0))
  1376. #else /* !MSWIN */
  1377.     if (ecrec.zipfile_comment_length && (zflag > 0 || (zflag == 0 && !qflag)))
  1378. #endif /* ?MSWIN */
  1379.     {
  1380. #if 0
  1381. #ifndef MSWIN
  1382.         if (zflag == 0)       (add "&& single_zipfile" perhaps; unnecessary with
  1383.             printf("[%s] comment:\n", zipfn);  multiple zipfiles: "Archive:...")
  1384. #endif /* !MSWIN */
  1385. #endif /* 0 */
  1386.         if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
  1387.             fprintf(stderr, "\ncaution:  zipfile comment truncated\n");
  1388.             error = PK_WARN;
  1389.         }
  1390.     }
  1391.     return error;
  1392.  
  1393. } /* end function uz_end_central() */
  1394.  
  1395.  
  1396.  
  1397.  
  1398.  
  1399. /**************************************/
  1400. /*  Function process_cdir_file_hdr()  */
  1401. /**************************************/
  1402.  
  1403. int process_cdir_file_hdr()    /* return PK-type error code */
  1404. {
  1405.     int error;
  1406.  
  1407.  
  1408. /*---------------------------------------------------------------------------
  1409.     Get central directory info, save host and method numbers, and set flag
  1410.     for lowercase conversion of filename, depending on the OS from which the
  1411.     file is coming.
  1412.   ---------------------------------------------------------------------------*/
  1413.  
  1414.     if ((error = get_cdir_file_hdr()) != 0)
  1415.         return error;
  1416.  
  1417.     pInfo->hostnum = MIN(crec.version_made_by[1], NUM_HOSTS);
  1418. /*  extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
  1419.  
  1420.     pInfo->lcflag = 0;
  1421.     if (!U_flag)   /* as long as user hasn't specified case-preservation */
  1422.         switch (pInfo->hostnum) {
  1423.             case FS_FAT_:     /* PKZIP and zip -k store in uppercase */
  1424.             case ATARI_:      /* MS-DOS filesystem */
  1425.             case CPM_:        /* like MS-DOS, right? */
  1426.             case VM_CMS_:     /* all caps? */
  1427.             case TOPS20_:
  1428.         /*  case Z_SYSTEM_:   ? */
  1429.         /*  case QDOS_:       ? */
  1430.                 pInfo->lcflag = 1;   /* convert filename to lowercase */
  1431.                 break;
  1432.  
  1433.         /*  case VMS_:   Info-ZIP's VMS Zip converts filenames to lowercase */
  1434.             default:     /* AMIGA_, FS_HPFS_, FS_NTFS_, MAC_, UNIX_, */
  1435.                 break;   /*  (Z_SYSTEM_):  no conversion */
  1436.         }
  1437.  
  1438.     /* do Amigas (AMIGA_) also have volume labels? */
  1439.     if (IS_VOLID(crec.external_file_attributes) &&
  1440.         (pInfo->hostnum == FS_FAT_ || pInfo->hostnum == FS_HPFS_ ||
  1441.          pInfo->hostnum == FS_NTFS_ || pInfo->hostnum == ATARI_))
  1442.     {
  1443.         pInfo->vollabel = TRUE;
  1444.         pInfo->lcflag = 0;        /* preserve case of volume labels */
  1445.     } else
  1446.         pInfo->vollabel = FALSE;
  1447.  
  1448.     return PK_COOL;
  1449.  
  1450. } /* end function process_cdir_file_hdr() */
  1451.  
  1452.  
  1453.  
  1454.  
  1455.  
  1456. /***************************************/
  1457. /*  Function process_local_file_hdr()  */
  1458. /***************************************/
  1459.  
  1460. int process_local_file_hdr()    /* return PK-type error code */
  1461. {
  1462.     local_byte_hdr byterec;
  1463.  
  1464.  
  1465. /*---------------------------------------------------------------------------
  1466.     Read the next local file header and do any necessary machine-type con-
  1467.     versions (byte ordering, structure padding compensation--do so by copy-
  1468.     ing the data from the array into which it was read (byterec) to the
  1469.     usable struct (lrec)).
  1470.   ---------------------------------------------------------------------------*/
  1471.  
  1472.     if (readbuf((char *)byterec, LREC_SIZE) <= 0)
  1473.         return PK_EOF;
  1474.  
  1475.     lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
  1476.     lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
  1477.  
  1478.     lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
  1479.     lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
  1480.     lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]);
  1481.     lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]);
  1482.     lrec.crc32 = makelong(&byterec[L_CRC32]);
  1483.     lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]);
  1484.     lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
  1485.     lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
  1486.     lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
  1487.  
  1488.     csize = (long) lrec.csize;
  1489.     ucsize = (long) lrec.ucsize;
  1490.  
  1491.     if ((lrec.general_purpose_bit_flag & 8) != 0) {
  1492.         /* can't trust local header, use central directory: */
  1493.         lrec.crc32 = pInfo->crc;
  1494.         csize = (long)(lrec.csize = pInfo->compr_size);
  1495.     }
  1496.  
  1497.     return PK_COOL;
  1498.  
  1499. } /* end function process_local_file_hdr() */
  1500.